#include "uart.h"
#include <termios.h>
#include <unistd.h>

#ifndef ARR_COUNTOF
#define ARR_COUNTOF(a)   (sizeof(a) / sizeof(a[0]))
#endif 

// /usr/include/bits/termios.h 
// struct termios {
//     tcflag_t c_iflag; /* input mode flags */
//     tcflag_t c_oflag; /* output mode flags */
//     tcflag_t c_cflag; /* control mode flags */
//     tcflag_t c_lflag; /* local mode flags */
//     cc_t c_line;      /* line discipline */
//     cc_t c_cc[NCCS]; /* control characters */
//     speed_t c_ispeed; /* input speed */
//     speed_t c_ospeed; /* output speed */
//     #define _HAVE_STRUCT_TERMIOS_C_ISPEED 1
//     #define _HAVE_STRUCT_TERMIOS_C_OSPEED 1
//  };
 

int uatr_open(const char *dev)
{
    return open(dev, O_RDWR | O_NOCTTY); /*  O_NOCTTY 标志，该标志用于告知系统/dev/ttymxc2 它不会成为进程的控
制终端 */
}

int uart_get_old_cfg(int fd, struct termios *old_cfg)
{
    return  tcgetattr(fd, old_cfg);
}

int uart_cfg(uart_cfg_t *cfg)
{
    int ret;
    int i;
    struct termios new_cfg = {0};

    /* 配置为原始模式  */
    ret = cfmakeraw(&new_cfg);  

    /*  使能接收  */ 
    new_cfg.c_cflag |= CREAD; 

    /* 配置波特率 */
    unsigned int bauindex[] = {1200, 1800,   2400, 4800,  9600,  19200,   38400,   57600, 115200, 230400, 460800, 500000};
    speed_t speeds[]        = {B1200, B1800, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000};
    speed_t speed = B115200;   /* 默认配置为 115200 */
    for (i = 0; i < ARR_COUNTOF(bauindex); i++)
    {
        if (bauindex[i] == cfg->baudrate)
        {
            speed = speeds[i];
            break;
        }
    }
    /* 设置波特率 */
    ret = cfsetspeed(&new_cfg, speed);
    if (ret < 0)
    {
        fprintf(stderr, "cfsetspeed error: %s\n", strerror(errno)); 
        return -1; 
    }

    /* 设置数据位 */
    unsigned char bits[] = {5, 6, 7, 8};
    unsigned char c_flag_bits[] = {CS5, CS6, CS7, CS8};
    new_cfg.c_cflag &= ~CSIZE;   /*  CSIZE 位掩码清零 */
    for (i = 0; i < ARR_COUNTOF(bits); i++)
    {
        if (bits[i] == cfg->bits)
        {
            new_cfg.c_cflag |= c_flag_bits[i];  
            break; 
        } 
    }
    
    switch (cfg->parity)
    {
        case 'N':      /* 设置为无校验 */
            new_cfg.c_cflag &= ~PARENB; 
            new_cfg.c_iflag &= ~INPCK; 
            break;
        case 'O' :     /* 设置为奇校验 */
            new_cfg.c_cflag |= (PARODD | PARENB); 
            new_cfg.c_iflag |= INPCK; 
            break;  
        case 'E' :       /* 设置为偶校验 */
            new_cfg.c_cflag |= PARENB; 
            new_cfg.c_cflag &= ~PARODD; /*  清除 PARODD 标志，配置为偶校验  */ 
            new_cfg.c_iflag |= INPCK; 
            break;
        default:
            new_cfg.c_cflag &= ~PARENB; 
            new_cfg.c_iflag &= ~INPCK; 
            break;
    }

    switch (cfg->stop_bit)
    {
        case 1:
            /*  将停止位设置为1个比特  */ 
            new_cfg.c_cflag &= ~CSTOPB; 
            break;
        case 2:
            /* 将停止位设置为 2 个比特  */
            new_cfg.c_cflag |= CSTOPB; 
            break;
        default:
            /*  将停止位设置为1个比特  */ 
            new_cfg.c_cflag &= ~CSTOPB; 
            break;
    }

    // /* 将MIN 和 TIME 设置为 0， 即设置为非阻塞方式 */
    // new_cfg.c_cc[VTIME] = 0; 
    // new_cfg.c_cc[VMIN] = 0;

     /*  清空缓冲区  */ 
    if (0 > tcflush(fd, TCIOFLUSH)) 
    { 
        fprintf(stderr, "tcflush error: %s\n", strerror(errno)); 
        return -1;
    }

    /* 配置立即生效 */
    if (0 > tcsetattr(fd, TCSANOW, &new_cfg))
    {
        fprintf(stderr, "tcsetattr error: %s\n", strerror(errno)); 
        return -1; 
    }

    return ret;
}

int uart_write(int fd, char *buf, int len)
{
    return write(fd, buf, strlen(buf));
}

int uart_read(int fd, char *buf, int len)
{
    return read(fd, buf, len);
}